package com.bytebuddytest.classcreation;

import net.bytebuddy.ByteBuddy;
import net.bytebuddy.NamingStrategy;
import net.bytebuddy.description.type.TypeDescription;
import net.bytebuddy.dynamic.DynamicType;
import org.junit.jupiter.api.Assertions;
import org.junit.jupiter.api.DisplayName;
import org.junit.jupiter.api.Test;

/**
 * @author yutianhong
 * @version 1.0
 * @since 2023/08/14 20:47:00
 */
@DisplayName("byte-buddy naming strategy test")
public class ByteBuddyNamingStrategyTest {

    @Test
    public void testCustomClassName() {
        DynamicType.Unloaded<?> dynamicType = new ByteBuddy()
                .subclass(Object.class)
                .name("example.Type")
                .make();
        Class<?> dynamicClass = dynamicType.load(getClass().getClassLoader())
                .getLoaded();
        String className = dynamicClass.getName();
        System.out.println("fieldName = " + className);
        Assertions.assertEquals(className, "example.Type");
    }

    @Test
    public void testDefaultNamingStrategy1() {
        DynamicType.Unloaded<?> dynamicType = new ByteBuddy()
                .subclass(Foo.class)
                .make();
        Class<?> dynamicClass = dynamicType.load(getClass().getClassLoader())
                .getLoaded();
        String className = dynamicClass.getName();
        System.out.println("fieldName = " + className);
        Assertions.assertTrue(className.startsWith("com.bytebuddytest.classcreation.Foo$ByteBuddy$"));
    }

    @Test
    public void testDefaultNamingStrategy2() {
        // subclass from java.lang
        DynamicType.Unloaded<?> dynamicType = new ByteBuddy()
                .subclass(Object.class)
                .make();
        Class<?> dynamicClass = dynamicType.load(getClass().getClassLoader())
                .getLoaded();
        String className = dynamicClass.getName();
        System.out.println("fieldName = " + className);
        Assertions.assertTrue(className.startsWith("net.bytebuddy.renamed.java.lang.Object$ByteBuddy$"));
    }

    @Test
    public void testCustomNamingStrategy() {
        DynamicType.Unloaded<?> dynamicType = new ByteBuddy()
                .with(new NamingStrategy.AbstractBase() {
                    @Override
                    protected String name(TypeDescription superClass) {
                        return "i.love.ByteBuddy." + superClass.getSimpleName();
                    }
                })
                .subclass(Object.class)
                .make();
        Class<?> dynamicClass = dynamicType.load(getClass().getClassLoader())
                .getLoaded();
        String className = dynamicClass.getName();
        System.out.println("fieldName = " + className);
        Assertions.assertEquals(className, "i.love.ByteBuddy.Object");
    }

    @Test
    public void testCustomNamingStrategyWithSuffixingRandom() {
        DynamicType.Unloaded<?> dynamicType = new ByteBuddy()
                .with(new NamingStrategy.SuffixingRandom(
                        "test",
                        (NamingStrategy.Suffixing.BaseNameResolver) typeDescription ->
                                "i.love.ByteBuddy." + typeDescription.getSimpleName())
                )
                .subclass(Object.class)
                .make();
        Class<?> dynamicClass = dynamicType.load(getClass().getClassLoader())
                .getLoaded();
        String className = dynamicClass.getName();
        System.out.println("fieldName = " + className);
        Assertions.assertTrue(className.startsWith("i.love.ByteBuddy.Object$test$"));
    }

    @Test
    public void testImmutableObject() {
        ByteBuddy byteBuddy1 = new ByteBuddy();
        ByteBuddy byteBuddy2 = byteBuddy1.with(new NamingStrategy.SuffixingRandom("test"));
        Assertions.assertNotSame(byteBuddy1, byteBuddy2);
    }

}
